package com.suredy.core.ctrl;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.suredy.Constants;
import com.suredy.core.model.BaseModel;
import com.suredy.security.model.Role;
import com.suredy.security.model.User;

public class BaseCtrl {

	protected final String CODE_ERR_MSG = "err_msg";

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
	}

	protected HttpServletRequest getRequest() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	}

	protected String getContextPath() {
		return this.getRequest().getContextPath();
	}

	protected HttpSession getSession() {
		return this.getRequest().getSession(true);
	}

	protected void setSessionAttribute(String name, Object value) {
		if (StringUtils.isBlank(name))
			throw new IllegalArgumentException("Invalid parameter String[key].");

		this.getSession().setAttribute(name, value);
	}

	protected Object getSessionAttribute(String name) {
		if (StringUtils.isBlank(name))
			throw new IllegalArgumentException("Invalid parameter String[key].");

		return this.getSession().getAttribute(name);
	}

	protected void removeSessionAttribute(String name) {
		if (StringUtils.isBlank(name))
			throw new IllegalArgumentException("Invalid parameter String[key].");

		this.getSession().removeAttribute(name);
	}

	protected Object getAndRemoveSessionAttribute(String name) {
		if (StringUtils.isBlank(name))
			throw new IllegalArgumentException("Invalid parameter String[key].");

		Object val = this.getSessionAttribute(name);

		this.removeSessionAttribute(name);

		return val;
	}

	protected void clearSession() {
		HttpSession session = this.getSession();

		session.invalidate();
	}

	protected boolean isTheSameCheckCode(String checkCode) {
		if (StringUtils.isBlank(checkCode))
			return false;

		String code = (String) this.getSessionAttribute(Constants.SESSION_LOGIN_CHECK_CODE);

		return checkCode.equalsIgnoreCase(code);
	}

	protected User getUser() {
		Object obj = this.getSessionAttribute(Constants.SESSION_LOGIN_USER);

		return (User) obj;
	}

	protected void setUser(User user) {
		if (user == null)
			return;

		this.setSessionAttribute(Constants.SESSION_LOGIN_USER, user);
	}

	@SuppressWarnings("unchecked")
	protected List<Role> getUserRoles() {
		Object obj = this.getSessionAttribute(Constants.SESSION_USER_ROLES);

		return (List<Role>) obj;
	}

	protected void setUserRoles(List<Role> roles) {
		if (roles == null)
			return;

		this.setSessionAttribute(Constants.SESSION_USER_ROLES, roles);
	}

	protected boolean isSystemManager() {
		Object obj = this.getSessionAttribute(Constants.SESSION_SYS_MANAGER);

		if (obj == null || !Boolean.class.isInstance(obj))
			return false;

		return (boolean) obj;
	}

	protected void setSystemManager(boolean is) {
		this.setSessionAttribute(Constants.SESSION_SYS_MANAGER, is);
	}

	protected boolean isProjCreater() {
		Object obj = this.getSessionAttribute(Constants.SESSION_PROJ_CREATER);

		if (obj == null || !Boolean.class.isInstance(obj))
			return false;

		return (boolean) obj;
	}

	protected void setProjCreater(boolean is) {
		this.setSessionAttribute(Constants.SESSION_PROJ_CREATER, is);
	}

	protected boolean isProjDeleter() {
		Object obj = this.getSessionAttribute(Constants.SESSION_PROJ_DELETER);

		if (obj == null || !Boolean.class.isInstance(obj))
			return false;

		return (boolean) obj;
	}

	protected void setProjDeleter(boolean is) {
		this.setSessionAttribute(Constants.SESSION_PROJ_DELETER, is);
	}

	protected boolean isProjUpdater() {
		Object obj = this.getSessionAttribute(Constants.SESSION_PROJ_UPDATER);

		if (obj == null || !Boolean.class.isInstance(obj))
			return false;

		return (boolean) obj;
	}

	protected void setProjUpdater(boolean is) {
		this.setSessionAttribute(Constants.SESSION_PROJ_UPDATER, is);
	}

	/**
	 * 将String字符串转化为对象属性对应的类型
	 * 
	 * @param clazz
	 * @param field
	 * @param data
	 * @param format
	 * @return
	 */
	@SuppressWarnings("all")
	protected Object stringToFieldValue(Class<? extends BaseModel> clazz, String field, String data, String format) throws Exception {
		if (clazz == null || StringUtils.isBlank(field) || StringUtils.isBlank(data))
			return null;

		Field f = null;

		try {
			String[] fields = field.split("\\.");
			Object firstObj = clazz.newInstance();
			Object lastObj = firstObj;

			for (int i = 0; i < fields.length - 1; i++) {
				String fName = fields[i];

				f = lastObj.getClass().getDeclaredField(fName);
				f.setAccessible(true);

				f.set(lastObj, lastObj = f.getType().newInstance());

				f.setAccessible(false);
			}

			String lastField = fields[fields.length - 1];
			f = lastObj.getClass().getDeclaredField(lastField);
			f.setAccessible(true);

			Map<String, Object> tmp = new HashMap<String, Object>();

			// 特殊处理日期类型
			if (Date.class == f.getType()) {
				tmp.put(lastField, new SimpleDateFormat(format).parse(data));
			} else if (f.getType().isEnum()) {
				Class fClass = f.getType();
				tmp.put(lastField, Enum.valueOf(fClass, data));
			} else {
				tmp.put(lastField, data);
			}

			f.setAccessible(false);

			BeanUtils.populate(lastObj, tmp);

			f = firstObj.getClass().getDeclaredField(fields[0]);
			f.setAccessible(true);

			Object val = f.get(firstObj);

			f.setAccessible(false);

			if (val == null)
				throw new RuntimeException("Convert to field object error.");

			return val;
		} catch (Exception e) {
			throw e;
		} finally {
			if (f != null)
				f.setAccessible(false);
		}
	}

}
